use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use axum::extract::{Path, State};
use axum::response::Html;
use axum::Router;
use axum::routing::get;
use crate::{HttpSubcommand};


#[derive(Debug)]
struct HttpServeState {
    path: PathBuf,
}

pub async fn serve(opt: HttpSubcommand) -> anyhow::Result<()> {
    match opt {
        HttpSubcommand::Serve(opt) => {
            let addr = SocketAddr::from(([0, 0, 0, 0], opt.port));
            println!("Serving {:?} on port {}", &opt.path, &opt.port);
            let state = HttpServeState { path: opt.path.clone() };
            // let dir_service = ServeDir::new("static")
            //     .append_index_html_on_directories(true)
            //     .precompressed_gzip()
            //     .precompressed_br()
            //     .precompressed_deflate()
            //     .precompressed_zstd();
            let app = Router::new()

                //.nest_service("/tower",dir_service)
                .route("/*path", get(file_handler))
                .with_state(Arc::new(state));

            let listener = tokio::net::TcpListener::bind(addr).await?;
            axum::serve(listener, app).await?;
        }
    }
    Ok(())
}

async fn file_handler(State(state): State<Arc<HttpServeState>>
                      , Path(path): Path<String>) -> Html<String> {
    let mut p = std::path::Path::new(&state.path).join(path);
    println!("{:?}", &p);
    if !p.exists() {
        return Html(String::from("File  not foud "));
    };

    if p.is_dir() {
        let mut content = String::new();
        content.push_str("<!DOCTYPE html><html lang=\"zh-CN\"><ul> <head></head> <body>");
        let entries = std::fs::read_dir(p).unwrap();
        for entrie in entries {
            if let Ok(t) = entrie {
                content.push_str("<li>");
                let li = format!("{}", t.path().display());
                let li1 = li.clone();
                content.push_str(li1.as_str());
                content.push_str("</li>");
            }
        }
        content.push_str("</ul><body></html>");
        return Html(content);
    }

    return match tokio::fs::read_to_string(&p).await {
        Ok(content) => {
            let t = content;
            Html(t)
        }
        Err(err) => {
            Html(String::from("file not found"))
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    async fn test_file_handler() {}
}